package org.javacore.concurrent;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by Fan
 * Date: 2019/9/15
 * Time: 17:41
 * Description:使用CountDownLatch与CyclicBarrier实现交替打印Foo,Bar
 * CountDownLatch保证组内任务的执行先后顺序
 * CyclicBarrier保证任务按组进行
 */
public class CyclicBarrierLatchA {
    // 线程池
    private final static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
            .setNameFormat("demo-pool-%d").build();
    private final static ExecutorService service = new ThreadPoolExecutor(5, 200,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    public static void main(String[] args) {
        CyclicBarrierLatchA.FooBar f = new CyclicBarrierLatchA.FooBar(4);
        service.execute(() -> {
            f.foo(()->{
                System.out.println("Foo");
            });
        });
        service.execute(() -> {
            f.bar(()->{
                System.out.println("Bar");
            });
        });
        service.shutdown();
    }

    public static class FooBar {
        private int n;
        private CountDownLatch a;
        private CyclicBarrier barrier;// 使用CyclicBarrier保证任务按组执行

        public FooBar(int n) {
            this.n = n;
            a = new CountDownLatch(1);
            barrier = new CyclicBarrier(2);// 保证每组内有两个任务
        }

        public void foo(Runnable printFoo) {
            try {
                for (int i = 0; i < n; i++) {
                    printFoo.run();
                    a.countDown();// printFoo方法完成调用countDown
                    barrier.await();// 等待printBar方法执行完成
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public void bar(Runnable printBar) {
            try {
                for (int i = 0; i < n; i++) {
                    a.await();// 等待printFoo方法先执行
                    printBar.run();
                    a = new CountDownLatch(1); // 保证下一次依旧等待printFoo方法先执行
                    barrier.await();// 等待printFoo方法执行完成
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
